<?php

/**
 * Description of Validator
 *
 * @author Ervinne
 */
class Validator {

    protected $errorHandler;
    protected $items;
    
    protected $rules = [
        'required', 'alphanumeric', 'minlength', 'maxlength', 'email', 'match'
    ];
    public $errorMessages = [
        'required' => 'The :field field is required',
        'alphanumeric' => 'The :field field must be alphanumeric',
        'minlength' => 'The :field field must be a minimum of :satisfier characters',
        'maxlength' => 'The :field field must be a maximum of :satisfier characters',
        'email' => 'The :field field must be a valid email address',
        'match' => 'The :field field must match the :satisfier field'
    ];

    public function __construct(ErrorHandler $errorHandler) {
        $this->errorHandler = $errorHandler;
    }

    public function check($items, $rules) {

        $this->items = $items;
        foreach ($items as $item => $value) {

            if (in_array($item, array_keys($rules))) {

                $this->validate([
                    'field' => $item,
                    'value' => $value,
                    'rules' => $rules[$item]
                ]);
            }
        }

        //  allow chaining
        return $this;
    }

    public function fails() {
        return $this->errorHandler->has_errors();
    }

    public function errors() {
        return $this->errorHandler;
    }

    protected function validate($item) {

        $field = $item['field'];
        $value = $item['value'];

        foreach ($item['rules'] as $rule => $satisfier) {
            if (in_array($rule, $this->rules)) {
                //  if a rule method returns false, add a new error in the error handler
                if (!call_user_func_array([$this, $rule], [$field, $value, $satisfier])) {
                    //  build the error message
                    $errorMessage = str_replace(
                            [':field', ':satisfier'], [$field, $satisfier], $this->errorMessages[$rule]
                    );

                    $this->errorHandler->add_error($errorMessage, $field);
                }
            }
        }
    }

    //  rule methods

    protected function required($field, $value, $satisfier) {
        $trimmedValue = trim($value);
        return !empty($trimmedValue);
    }

    protected function alphanumeric($field, $value, $satisfier) {
        return ctype_alnum($value);
    }
    
    protected function minlength($field, $value, $satisfier) {
        return mb_strlen($value) >= $satisfier;
    }

    protected function maxlength($field, $value, $satisfier) {
        return mb_strlen($value) <= $satisfier;
    }

    protected function email($field, $value, $satisfier) {
        return filter_var($value, FILTER_VALIDATE_EMAIL);
    }
    
    protected function match($field, $value, $satisfier) {
        return $value === $this->items[$satisfier];
    }

}
